package com.treasure.mall.biz.service.core.user.impl;

import com.treasure.mall.biz.base.AbstractSearchableCrudService;
import com.treasure.mall.biz.base.SpecificationAndSort;
import com.treasure.mall.biz.bo.config.BasicsConfig;
import com.treasure.mall.biz.dto.BaseSaveDTO;
import com.treasure.mall.biz.dto.BaseSearchDTO;
import com.treasure.mall.biz.dto.condition.UserSearchCondition;
import com.treasure.mall.biz.dto.user.*;
import com.treasure.mall.biz.entity.auth.SystemManager;
import com.treasure.mall.biz.entity.integral.UserIntegralLogPO;
import com.treasure.mall.biz.entity.log.UserChangeLogPO;
import com.treasure.mall.biz.entity.user.*;
import com.treasure.mall.biz.mapstruct.UserMapStruct;
import com.treasure.mall.biz.repository.integral.UserIntegralLogRepository;
import com.treasure.mall.biz.repository.log.UserChangeLogRepository;
import com.treasure.mall.biz.repository.user.UserRelaxRepository;
import com.treasure.mall.biz.repository.user.UserRepository;
import com.treasure.mall.biz.repository.user.WechatUserAppRepository;
import com.treasure.mall.biz.repository.user.WechatUserRepository;
import com.treasure.mall.biz.service.core.BaseConfigService;
import com.treasure.mall.biz.service.core.log.AdvanceLogService;
import com.treasure.mall.biz.service.core.user.IMUSerSigService;
import com.treasure.mall.biz.service.core.user.MerchantService;
import com.treasure.mall.biz.service.core.user.UserService;
import com.treasure.mall.biz.service.core.user.WeChatService;
import com.treasure.mall.biz.vo.summary.SummaryVO;
import com.treasure.mall.biz.vo.user.*;
import com.treasure.mall.zbq.common.*;
import com.treasure.mall.zbq.common.base.ApiResult;
import com.treasure.mall.zbq.common.base.ResultCodeEnum;
import com.treasure.mall.zbq.common.base.TwoTuple;
import com.treasure.mall.zbq.common.exception.ApiException;
import com.treasure.mall.zbq.common.ienum.SystemEnums;
import com.treasure.mall.zbq.common.ienum.log.AdvanceLogType;
import com.treasure.mall.zbq.common.ienum.log.LogDataType;
import com.treasure.mall.zbq.common.ienum.log.UserChangeLogType;
import com.treasure.mall.zbq.common.ienum.user.UserEnums;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 *
 * +---------------------------------------------------------
 * * @package: com.treasure.mall.biz.service.core.user.impl
 * * @author: guomw (guomwchen@foxmail.com)
 * * @date: 2020/6/11 11:33
 * * @since: V1.0.0
 * +---------------------------------------------------------
 * 注意：本内容仅限于内部传阅，禁止外泄以及用于其他的商业目的
 * Copyright 2019-2022 com.treasure.mall.biz.service.core.user.impl Inc. All rights reserved.
 */
@Slf4j
@Service
public class UserServiceImpl extends AbstractSearchableCrudService<UserPO, Long> implements UserService {


    private UserRepository userRepository;
    @Resource
    private WeChatService weChatService;
    @Resource
    private AdvanceLogService advanceLogService;
    @Resource
    private UserRelaxRepository userRelaxRepository;
    @Resource
    private WechatUserRepository wechatUserRepository;
    @Resource
    private UserChangeLogRepository userChangeLogRepository;
    @Resource
    private BaseConfigService baseConfigService;
    @Resource
    private MerchantService merchantService;
    @Autowired
    private IMUSerSigService imuSerSigService;
    @Autowired
    private WechatUserAppRepository wechatUserAppRepository;
    @Resource
    private UserIntegralLogRepository integralLogRepository;

    @Autowired
    protected UserServiceImpl(UserRepository repository) {
        super(repository);
        this.userRepository = repository;
    }

    @Override
    public UserPO findById(Long aLong) {
        return checkMerchant(super.findById(aLong));
    }

    @Override
    public UserPO findByUnionId(String unionId) {
        WechatUser wechatUser = wechatUserRepository.findFirstByUnionId(unionId);
        if (wechatUser != null) {
            return findByUsername(wechatUser.getPhoneNumber());
        }
        return null;
    }

    /**
     * 根据上线ID获取上线用户
     *
     * @param userId
     * @return
     */
    @Override
    public UserPO findByParentId(Long userId) {
        return userRepository.findById(userId).orElse(null);
    }


    @Override
    protected SpecificationAndSort<UserPO> specificationAndSort(BaseSearchDTO searchDTO) {
        UserSearchCondition condition = (UserSearchCondition) searchDTO;
        Specification<UserPO> specification = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(cb.equal(root.get(UserPO_.deleted), false));

            if (StringUtils.isNotBlank(condition.getKeyword())) {
                predicates.add(cb.or(
                        cb.like(root.get(UserPO_.mobile), likeAll(condition.getKeyword())),
                        cb.like(root.get(UserPO_.nickName), likeAll(condition.getKeyword()))
                ));
            }

            if (condition.getStatus() != -1) {
                predicates.add(cb.equal(root.get(UserPO_.enabled), condition.getStatus() == 1));
            }

            if (condition.getParentId() != null && condition.getParentId() > 0) {
                predicates.add(cb.equal(root.get(UserPO_.parentId), condition.getParentId()));
            }

            if (StringUtils.isNotBlank(condition.getTreePath())) {
//                predicates.add(cb.like(root.get(UserPO_.treePath), likeRight(condition.getTreePath())));
                predicates.add(cb.notEqual(root.get(UserPO_.userId), condition.getUserId()));

                predicates.add(cb.or(
                        cb.like(root.get(UserPO_.treePath), likeAll("|" + condition.getUserId() + "|")),
                        cb.equal(root.get(UserPO_.parentId), condition.getUserId())
                ));
            }

            if (condition.getUserType() != null) {
                if (condition.getUserType().equals(UserEnums.UserType.MEMBER)) {
                    predicates.add(cb.or(
                            cb.equal(root.get(UserPO_.userLevel), UserEnums.UserLevel.LEVEL_XIN_XIU),
                            cb.equal(root.get(UserPO_.userLevel), UserEnums.UserLevel.LEVEL_DA_REN))
                    );
                } else {
                    predicates.add(cb.or(
                            cb.equal(root.get(UserPO_.userLevel), UserEnums.UserLevel.GENERAL),
                            cb.equal(root.get(UserPO_.userLevel), UserEnums.UserLevel.SINGLE_FAN))
                    );
                }
            }

            if (condition.getUserLevel() != null) {
                predicates.add(cb.equal(root.get(UserPO_.userLevel), condition.getUserLevel()));
            }


            if (!org.springframework.util.StringUtils.isEmpty(condition.getBeginTime())) {
                LocalDateTime beginTime = StringUtilsExt.localDateTimeFormat(condition.getBeginTime());
                predicates.add(cb.greaterThanOrEqualTo(root.get(UserPO_.createTime), beginTime));
            }
            if (!org.springframework.util.StringUtils.isEmpty(condition.getEndTime())) {
                LocalDateTime endTime = StringUtilsExt.localDateTimeFormat(condition.getEndTime());
                predicates.add(cb.lessThanOrEqualTo(root.get(UserPO_.createTime), endTime));
            }

            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
        };
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        return new SpecificationAndSort<>(specification, sort);
    }

    /**
     * @param token
     * @return
     */
    @Override
    public UserPO findByToken(String token) {
        return checkMerchant(userRepository.findFirstByLoginToken(token));
    }

    /**
     * 根据用户名查找用户
     *
     * @param username
     * @return
     */
    @Override
    public UserPO findByUsername(String username) {
        return checkMerchant(userRepository.findByMobile(username));
    }

    private UserPO checkMerchant(UserPO userPO) {
        if (userPO == null) {
            return null;
        }
        if (userPO.getMerchantId() != null && userPO.getMerchantId() > 0) {
            userPO.setMerchant(merchantService.findById(userPO.getMerchantId()));
        }
        return userPO;
    }

    /**
     * 我的下线
     *
     * @param condition
     * @return
     */
    @Override
    public List<UserPO> findChildren(UserSearchCondition condition) {
        SpecificationAndSort<UserPO> specificationAndSort = specificationAndSort(condition);
        return userRepository.findAll(specificationAndSort.getSpecification(), specificationAndSort.getSort());
    }

    @Override
    public List<UserPO> getSuperiorUserList(Long userId) {
        UserPO userPO = findById(userId);
        if (userPO == null) {
            return new ArrayList<>();
        }
        List<Long> idList = userPO.getSuperiorUserIdList();
        //调整顺序
        List<UserPO> superiorUserListSorted = new ArrayList<>();
        if (idList != null && idList.size() > 0) {
            List<UserPO> superiorUserList = userRepository.getUserList(idList);
            for (Long id : idList) {
                superiorUserList.stream().filter(x -> x.getUserId().equals(id)).findFirst().ifPresent(superiorUserListSorted::add);
            }
        }
        return superiorUserListSorted;
    }

    /**
     * 修改用户真实姓名
     *
     * @param userId
     * @param name
     */
    @Override
    public void modifyUserRealName(Long userId, String name) {
        userRepository.modifyUserRealName(userId, name);
    }

    /**
     * 根据code获取用户信息
     *
     * @param code
     * @return
     */
    @Override
    public UserVO loginByWechatCode(String code) {
        //获取微信信息
        WechatUser wechatUser = weChatService.loginByCode(code);
        if (wechatUser == null) {
            throw new ApiException(ApiResult.error("未注册用户，需进行授权"));
        }
        Specification<UserPO> specification = (root, query, cb) -> {
            List<Predicate> predicateList = new ArrayList<>();
            predicateList.add(cb.equal(root.get(UserPO_.wechatUser).get(WechatUser_.phoneNumber), wechatUser.getPhoneNumber()));
            return cb.and(predicateList.toArray(new Predicate[0]));
        };
        UserPO user = userRepository.findOne(specification).orElse(null);
        if (user != null) {
//            todo: 取消token 单设备登录限制
            if (StringUtils.isEmpty(user.getLoginToken())) {
                String token = getLoginToken();
                user.setLoginToken(token);
                userRepository.modifyUserLoginToken(user.getUserId(), token);
            }
            UserVO vo = UserMapStruct.INSTANCE.po2vo(user);
            vo.setUserId(user.getUserId());
            return vo;
        }
        throw new ApiException(ApiResult.error("未注册用户，需进行授权"));
    }

    /**
     * 微信登录
     *
     * @param dto
     * @return
     */
    @Override
    public UserVO loginAsWechatApp(LoginDTO dto) throws WxErrorException {
        //获取微信信息
        WechatUser wechatUser = weChatService.login(dto);
        String loginToken = getLoginToken();
        Specification<UserPO> specification = (root, query, cb) -> {
            List<Predicate> predicateList = new ArrayList<>();
            predicateList.add(cb.equal(root.get(UserPO_.wechatUser).get(WechatUser_.phoneNumber), wechatUser.getPhoneNumber()));
            return cb.and(predicateList.toArray(new Predicate[0]));
        };
        UserPO user = userRepository.findOne(specification).orElse(null);
        if (user != null) {
//            todo: 取消token 单设备登录限制
            if (StringUtils.isEmpty(user.getLoginToken())) {
                user.setLoginToken(loginToken);
                userRepository.modifyUserLoginToken(user.getUserId(), loginToken);
            }
            UserVO vo = UserMapStruct.INSTANCE.po2vo(user);
            vo.setUserId(user.getUserId());
            return vo;
        }

        user = new UserPO();
        user.setEnabled(true);
        user.setAvatar(wechatUser.getAvatarUrl());
        user.setMobile(wechatUser.getPhoneNumber());
        user.setNickName(wechatUser.getNickname());
        user.setUserType(UserEnums.UserType.GENERAL);
        user.setRegisterClient(SystemEnums.Client.WECHAT_MICRO_APP);
        user.setUserLevel(UserEnums.UserLevel.GENERAL);
        user.setParentId(0L);
        //用户登录token
        user.setLoginToken(loginToken);
        //保存
        user = userRepository.saveAndFlush(user);

        wechatUser.setUserId(user.getUserId());
        wechatUserRepository.save(wechatUser);

        user.setWechatUser(wechatUser);
        user.setTreePath("|" + user.getUserId() + "|");
        user = userRepository.save(user);

        return UserMapStruct.INSTANCE.po2vo(user);
    }

    /**
     * app微信登录
     * 如果用户已绑定手机，则直接返回用户信息
     * 否则返回null，客户端需要告知用户进行绑定手机
     *
     * @param dto
     * @return
     */
    @Override
    public UserVO loginAsApp(AppLoginDTO dto) {
        WechatUserApp userApp = getWechatUserApp(dto);
        if (userApp.getUserId() != null && userApp.getUserId() > 0) {
            return this.who(userApp.getUserId(), 0L);
        }
        throw new ApiException(ApiResult.error(ResultCodeEnum.UNRECOGNIZED_IDENTITY));
    }

    /**
     * app授权问题
     *
     * @param dto
     * @return
     */
    @Override
    public UserVO appAuthWechat(AppLoginDTO dto) {
        getWechatUserApp(dto);
        AppLoginAsMobileDTO mobileDTO = new AppLoginAsMobileDTO();
        mobileDTO.setOpenId(dto.getOpenId());
        mobileDTO.setMobile(dto.getMobile());
        return loginAsAppBindMobile(mobileDTO);
    }

    private WechatUserApp getWechatUserApp(AppLoginDTO dto) {
        WechatUserApp userApp = wechatUserAppRepository.findById(dto.getOpenId()).orElse(null);
        if (userApp == null) {
            userApp = new WechatUserApp();
            userApp.setAvatarUrl(dto.getHeadImg());
            userApp.setCity(dto.getCity());
            userApp.setSex("男".equals(dto.getGender()) ? 1 : 0);
            userApp.setCountry("中国");
            userApp.setNickName(dto.getNickName());
            userApp.setOpenId(dto.getOpenId());
            userApp.setProvince(dto.getProvince());
            userApp.setUnionId(dto.getUnionId());
            wechatUserAppRepository.save(userApp);
        }
        WechatUser wechatUser = wechatUserRepository.findFirstByUnionId(dto.getUnionId());
        if (wechatUser != null) {
            UserPO user = findByUsername(wechatUser.getPhoneNumber());
            if (user != null) {
                userApp.setUserId(user.getUserId());
            }
        }

        return userApp;
    }


    /**
     * 手机登录或绑定手机
     *
     * @param dto
     * @return
     */
    @Override
    public UserVO loginAsAppBindMobile(AppLoginAsMobileDTO dto) {
        UserPO user = findByUsername(dto.getMobile());
        WechatUser wechatUser = wechatUserRepository.findTopByPhoneNumber(dto.getMobile());
        WechatUserApp userApp = null;
        if (StringUtils.isNotBlank(dto.getOpenId())) {
            userApp = wechatUserAppRepository.findById(dto.getOpenId()).orElse(null);
            if (userApp != null) {
                userApp.setPhoneNumber(dto.getMobile());
                userApp.setPurePhoneNumber(dto.getMobile());
            }
            if (user != null && userApp != null) {
                userApp.setUserId(user.getUserId());
                wechatUserAppRepository.save(userApp);
            }
        }
        if (wechatUser == null) {
            wechatUser = new WechatUser(userApp);

        }
        if (userApp != null) {
            wechatUser.setUnionId(userApp.getUnionId());
        }
        if (StringUtils.isEmpty(wechatUser.getNickname())) {
            wechatUser.setNickname(dto.getMobile());
        }
        wechatUser.setPhoneNumber(dto.getMobile());
        wechatUser.setPurePhoneNumber(dto.getMobile());
        if (StringUtils.isNotBlank(dto.getOpenId())) {
            wechatUser.setOpenId(dto.getOpenId());
        }
        wechatUser.setSex(1);
        wechatUserRepository.save(wechatUser);

        if (user == null) {
            user = new UserPO();
            user.setEnabled(true);
            user.setAvatar(wechatUser.getAvatarUrl());
            user.setMobile(wechatUser.getPhoneNumber());
            user.setNickName(wechatUser.getNickname());
            user.setUserType(UserEnums.UserType.GENERAL);
            if (dto.getClient() == 1) {
                user.setRegisterClient(SystemEnums.Client.IOS);
            } else {
                user.setRegisterClient(SystemEnums.Client.ANDROID);
            }
            user.setUserLevel(UserEnums.UserLevel.GENERAL);
            user.setParentId(0L);
            //用户登录token
            user.setLoginToken(getLoginToken());
            //保存
            user = userRepository.saveAndFlush(user);
            if (userApp != null) {
                userApp.setUserId(user.getUserId());
                wechatUserAppRepository.save(userApp);
            }
            user.setWechatUser(wechatUser);
            user.setTreePath("|" + user.getUserId() + "|");
            user = userRepository.save(user);
        } else {
            if (userApp != null) {
                userApp.setUserId(user.getUserId());
                wechatUserAppRepository.save(userApp);
            }
            user.setWechatUser(wechatUser);
            if (StringUtils.isEmpty(user.getLoginToken())) {
                //用户登录token
                user.setLoginToken(getLoginToken());
            }
            user = userRepository.save(user);
        }

        return who(user.getUserId(), 0L);
    }

    private String getLoginToken() {
        String loginToken = "";
        try {
            loginToken = RandomUtils.generateToken();
        } catch (UnsupportedEncodingException e) {

        }
        return loginToken;
    }

    /**
     * 获取用户信息
     *
     * @param userId     当前用户ID
     * @param fromUserId 邀请用户ID
     * @return
     * @throws Exception
     */
    @Override
    public UserVO who(Long userId, Long fromUserId) {
        UserPO user = this.findById(userId);
        UserVO vo;
        if (user != null) {
            vo = UserMapStruct.INSTANCE.po2vo(user);
            vo.setOpenId(user.getWechatUser().getOpenId());
            try {
                IMUSerSigPO imuSerSigPO = imuSerSigService.findById(userId);
                if (imuSerSigPO == null) {
                    imuSerSigPO = imuSerSigService.save(user);
                }
                IMSigVO userSigVO = new IMSigVO();
                userSigVO.setUserID(imuSerSigPO.getImUserId());
                userSigVO.setUserSig(imuSerSigPO.getUserSig());
                vo.setUserSig(userSigVO);
            } catch (Exception e) {

            }
            if (user.getWechatUser().getSex() != null) {
                vo.setSex(user.getWechatUser().getSex().equals(1) ? "男" : "女");
            }
            if (user.getMerchant() != null) {
                vo.setMerchantId(user.getMerchant().getMerchantId());
            }
            if (userId.equals(fromUserId) || user.getParentId() > 0) {
                return vo;
            }

            //如果存在邀请用户ID
            if (fromUserId != null && fromUserId > 0 && !user.getParentId().equals(fromUserId)) {
                UserPO parentPO = this.findById(fromUserId);
                if (parentPO != null) {

                    if (user.getUserId().equals(parentPO.getUserId())) {
//                        return new TwoTuple<>(false, "目标上级不能为自己");
                        return vo;
                    }
                    if (user.getParentId().equals(parentPO.getUserId())) {
//                        return new TwoTuple<>(false, "目标用户已经是上线了");
                        return vo;
                    }
                    if (parentPO.getTreePath().contains("|" + user.getUserId() + "|")) {
//                        return new TwoTuple<>(false, "目标上级是当前会员的下级会员");
                        return vo;
                    }

                    if (user.getTreePath().contains("|" + fromUserId + "|")) {
//                        目标是当前会员的上级会员
                        return vo;
                    }
                    user.setParentId(fromUserId);
                    user.setTreePath(appendTreePath(parentPO.getTreePath(), user.getUserId()));

                    String[] pathArray = parentPO.getTreePath().substring(1, parentPO.getTreePath().length() - 1).split("\\|");
                    List<UserRelax> userRelationsPOS = new ArrayList<>();
                    for (int i = 0; i < pathArray.length; i++) {
                        Long parentId = Long.valueOf(pathArray[i]);
                        int depth = pathArray.length - i;
                        UserRelax userRelationsPO = new UserRelax(depth, parentId, user.getUserId());
                        userRelationsPOS.add(userRelationsPO);
                    }
                    userRelaxRepository.saveAll(userRelationsPOS);
                    userRepository.save(user);
                }
            }
            return vo;
        }
        throw new ApiException(ApiResult.error(ResultCodeEnum.NOT_AUTHORITY));
    }


    /**
     * 修改用户信息
     *
     * @param dto
     */
    @Override
    public void modifyUserInfo(ModifyUserDTO dto) {
        UserPO user = this.findById(dto.getUserId());
        if (user == null) {
            return;
        }
        if (StringUtils.isNotBlank(dto.getNickName())) {
            userRepository.modifyUserNick(user.getUserId(), dto.getNickName());
        }
        if (StringUtils.isNotBlank(dto.getAvatar())) {
            userRepository.modifyUserAvatar(user.getUserId(), dto.getAvatar());
        }

        //修改分享邀请码
        if (StringUtils.isNotBlank(dto.getInviteQrcode())) {
            userRepository.modifyUserInviteQrcode(user.getUserId(), dto.getInviteQrcode());
        }
    }


    private String appendTreePath(String parentPath, Long userId) {
        return (StringUtils.isEmpty(parentPath) ? "|" : parentPath) + userId + "|";
    }

    @Override
    public UserPO save(BaseSaveDTO saveDTO) {
        return null;
    }


    /**
     * 获取我团队列表
     *
     * @param userId
     * @return
     */
    public List<UserPO> teamList(Long userId) {
        UserPO user = findById(userId);
        UserSearchCondition condition = new UserSearchCondition();
//        condition.setParentId(userId);
        condition.setUserId(userId);
        condition.setTreePath(user.getTreePath());
        SpecificationAndSort<UserPO> specificationAndSort = specificationAndSort(condition);
        return userRepository.findAll(specificationAndSort.getSpecification(), specificationAndSort.getSort());
    }

    /**
     * @param target
     * @return 团队中的高级买手人数
     */
    public Integer queryAdvancedBuyerTeamSize(UserPO target) {

        return 0;
    }

    @Override
    public TeamSummaryVO inviteSummary(Long userId) {
        return inviteSummary(userId, false);
    }

    /**
     * 获取邀请概要
     *
     * @param selectDr 是否查询达人数量
     * @param userId
     */
    @Override
    public TeamSummaryVO inviteSummary(Long userId, Boolean selectDr) {
        //如果商品店铺为开通，则无数据
//        if (user.getMerchant() == null) {
//            throw new ApiException(ApiResult.error(ResultCodeEnum.NOT_AUTHORITY));
//        }

        UserSearchCondition condition = new UserSearchCondition();
        condition.setParentId(userId);

        List<UserPO> userList = teamList(userId);
        // 普通粉丝，没有288开店
        List<UserPO> normalUsers = userList.stream().filter(r ->
                r.getUserLevel().equals(UserEnums.UserLevel.GENERAL)
        ).collect(Collectors.toList());

        //玩家 288开店用户
        List<UserPO> merchantUsers = userList.stream().filter(
                r -> r.getUserType().equals(UserEnums.UserType.MEMBER) && r.getMerchantPay()
        ).collect(Collectors.toList());

        //专属
        List<UserPO> buyerUsers = userList.stream().filter(r ->
                r.getUserLevel().equals(UserEnums.UserLevel.SINGLE_FAN)
        ).collect(Collectors.toList());

        SummaryVO normalSummary = new SummaryVO();
        normalSummary.setCount(normalUsers.size());
        normalSummary.setSum(BigDecimal.ZERO);

        //会员统计
        SummaryVO merchantSummary = new SummaryVO();
        merchantSummary.setCount(merchantUsers.size());
        merchantSummary.setSum(BigDecimal.ZERO);

        //专属粉丝统计
        SummaryVO buyerSummary = new SummaryVO();
        buyerSummary.setCount(buyerUsers.size());
        buyerSummary.setSum(BigDecimal.ZERO);


        TeamSummaryVO teamSummaryVO = new TeamSummaryVO();
        teamSummaryVO.setNormal(normalSummary);
        teamSummaryVO.setMerchant(merchantSummary);
        teamSummaryVO.setBuyer(buyerSummary);

        if (selectDr) {
            //玩家 288开店用户
            Integer xinXiuCount = userList.stream().filter(
                    r -> r.getUserLevel().equals(UserEnums.UserLevel.LEVEL_XIN_XIU)
            ).collect(Collectors.toList()).size();

            Integer drCount = userList.stream().filter(
                    r -> r.getUserLevel().equals(UserEnums.UserLevel.LEVEL_DA_REN)
            ).collect(Collectors.toList()).size();
            teamSummaryVO.setVipCount(xinXiuCount);
            teamSummaryVO.setDrCount(drCount);
        }


        return teamSummaryVO;
    }

    /**
     * 根据id 获取用户余额信息
     *
     * @param userId
     * @return
     */
    @Override
    public WalletVO myBalance(Long userId) {
        WalletVO walletVO = new WalletVO();
        UserPO user = this.findById(userId);
        walletVO.setIntegral(user.getIntegral());
        BalanceVO balanceVO = new BalanceVO();
        balanceVO.setBalance(user.getBalance());
        balanceVO.setBalanceInFuture(user.getBalanceInFuture());
        balanceVO.setHistoryTotalAmount(user.getHistoryTotalAmount());
        walletVO.setUser(balanceVO);
        MerchantPO merchant = user.getMerchant();
        if (merchant != null) {
            //商户货款信息数据
            BalanceVO merchantBalance = new BalanceVO();
            merchantBalance.setBalanceInFuture(merchant.getBalanceInFuture());
            merchantBalance.setBalance(merchant.getBalance());
            merchantBalance.setEarnestMoney(merchant.getEarnestMoney());
            merchantBalance.setHistoryTotalAmount(merchant.getHistoryTotalAmount());
            walletVO.setMerchant(merchantBalance);
        }
        return walletVO;
    }

    /**
     * 查找具备返利资格的用户
     *
     * @param userId 购买者ID
     * @return 最多返回两层
     */
    @Override
    public TwoTuple<UserPO, UserPO> getRebateParents(Long userId) {
        UserPO user = this.findById(userId);
        if (user == null) {
            return null;
        }
        UserPO first = null;
        UserPO second = null;
        if (user.getUserType().equals(UserEnums.UserType.MEMBER)) {
            first = user;
        }
        if (user.getUserLevel().equals(UserEnums.UserLevel.LEVEL_DA_REN)) {
            return new TwoTuple(first, null);
        }
        //获取上线所有的ID
        List<Long> parentIds = user.getSuperiorUserIdList();
        if (parentIds.isEmpty()) {
            return new TwoTuple(first, null);
        }
        List<UserPO> list = userRepository.getUserList(parentIds);
        if (list != null && list.size() > 0) {
            Collections.reverse(list);
            for (int i = 0; i < list.size(); i++) {
                UserPO item = list.get(i);
                if (first == null) {
                    //判断是否是新秀
                    first = item.getUserLevel().equals(UserEnums.UserLevel.LEVEL_XIN_XIU) ? item : null;

                    //如果不是新秀，就判断是否是达人
                    if (first == null) {
                        first = item.getUserLevel().equals(UserEnums.UserLevel.LEVEL_DA_REN) ? item : null;
                    }

                    //如果是达人，则直接退出循环
                    if (first != null && first.getUserLevel().equals(UserEnums.UserLevel.LEVEL_DA_REN)) {
                        break;
                    }
                    continue;
                }
                second = item.getUserLevel().equals(UserEnums.UserLevel.LEVEL_DA_REN) ? item : null;
                if (second != null) {
                    break;
                }
            }
        }

        //随便把用户的商家返回
        if (first != null && first.getMerchantId() != null && first.getMerchantId() > 0) {
            first.setMerchant(merchantService.findById(first.getMerchantId()));
        }

        if (second != null && second.getMerchantId() != null && second.getMerchantId() > 0) {
            second.setMerchant(merchantService.findById(second.getMerchantId()));
        }


        return new TwoTuple(first, second);
    }


    /**
     * 修改用户余额
     *
     * @param modifyBalanceDTO {@link ModifyBalanceDTO}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized void modifyBalance(ModifyBalanceDTO modifyBalanceDTO) {
        modifyUserBalance(modifyBalanceDTO, LogDataType.BALANCE);
    }

    /**
     * 修改用户待入账余额
     *
     * @param modifyBalanceDTO {@link ModifyBalanceDTO}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized void modifyBalanceInFuture(ModifyBalanceDTO modifyBalanceDTO) {
        //修改余额
        UserPO userPO = findById(modifyBalanceDTO.getId());
        BigDecimal before, after;
        // 修改前待入账余额
        before = userPO.getBalanceInFuture();
        // 修改后待入账余额
        after = before.add(modifyBalanceDTO.getAmount());
        if (MathUtils.greater(BigDecimal.ZERO, after)) {
            throw new ApiException(ApiResult.errorWith(ResultCodeEnum.ILLEGAL_STATE, "当前待入账余额不足"));
        }
        modifyUserBalance(modifyBalanceDTO, LogDataType.WAIT_BALANCE);
    }


    /**
     * 修改余额，并记录日志
     *
     * @param modifyBalanceDTO
     */
    private void modifyUserBalance(ModifyBalanceDTO modifyBalanceDTO, LogDataType dataType) {
        //修改余额
        UserPO userPO = findById(modifyBalanceDTO.getId());
        BigDecimal before, after;
        if (dataType == LogDataType.BALANCE) {
            // 修改可用余额
            before = userPO.getBalance();
            after = before.add(modifyBalanceDTO.getAmount());
            if (MathUtils.greater(BigDecimal.ZERO, after)) {
                throw new ApiException(ApiResult.errorWith(ResultCodeEnum.ILLEGAL_STATE, "当前账户余额不足"));

            }
            userRepository.modifyBalance(userPO.getUserId(), modifyBalanceDTO.getAmount());
            //添加历史总输入
            userRepository.modifyHistoryTotalAmount(userPO.getUserId(), modifyBalanceDTO.getAmount().abs());
        } else {
            before = userPO.getBalanceInFuture();
            after = before.add(modifyBalanceDTO.getAmount());
            if (MathUtils.greater(BigDecimal.ZERO, after)) {
                throw new ApiException(ApiResult.errorWith(ResultCodeEnum.ILLEGAL_STATE, "当前待入账余额不足"));
            }
            userRepository.modifyBalanceInFuture(userPO.getUserId(), modifyBalanceDTO.getAmount());
        }
        //记录日志
        advanceLogService.save(modifyBalanceDTO, dataType, before, after);
    }

    /**
     * 修改锁定余额
     * 目前只有下单时，如果使用了余额支付，需要锁定，其他地方不会锁定
     *
     * @param userId
     * @param amount 扣除为负，添加为正
     */
    @Override
    public void modifyLockBalance(Long userId, BigDecimal amount) {
        userRepository.modifyLockBalance(userId, amount);
    }

    @Override
    @Transactional(noRollbackFor = ApiException.class)
    public void modifyIntegral(ModifyIntegralDTO dto) {
        UserIntegralLogPO po = new UserIntegralLogPO();
        po.setUserId(dto.getUserId());
        po.setIntegral(dto.getIntegral());
        po.setLogType(dto.getLogType());
        po.setOrderId(dto.getOrderId());
        po.setLiveSessionId(dto.getLiveSessionId());

        while (true) {
            UserPO userPO = findById(dto.getUserId());
            if (dto.getIntegral() < 0 && userPO.getIntegral() < Math.abs(dto.getIntegral())) {
                po.setSuccess(false);
                po.setRemark("积分不足");
                integralLogRepository.save(po);
                throw new ApiException(ApiResult.error("积分不足"));
            }
            int index = userRepository.modifyIntegral(dto.getUserId(), dto.getIntegral(), userPO.getVersion());
            if (index > 0) {
                po.setSuccess(true);
                integralLogRepository.save(po);
                break;
            }
        }
    }

    /**
     * 变更上线
     *
     * @param user             要变更上线的代理商
     * @param targetParentUser 目标上线
     * @param manager          当前系统管理员
     * @return
     */
    @Override
    public TwoTuple<Boolean, String> changeParent(UserPO user, UserPO targetParentUser, SystemManager manager) {
        if (user == null || targetParentUser == null) {
            return new TwoTuple<>(false, "变更会员或目标上级不存在");
        }
        if (user.getUserId().equals(targetParentUser.getUserId())) {
            return new TwoTuple<>(false, "目标上级不能为自己");
        }
        if (user.getParentId().equals(targetParentUser.getUserId())) {
            return new TwoTuple<>(false, "目标用户已经是上线了");
        }
        if (targetParentUser.getTreePath().contains("|" + user.getUserId() + "|")) {
            return new TwoTuple<>(false, "目标上级是当前会员的下级会员");
        }

        UserPO oldParent = this.findById(user.getParentId());
        String oldParentName = oldParent != null ? oldParent.getMobile() : "";
        Long oldParentId = user.getParentId();
        String oldRealName = oldParent != null ? oldParent.getRealName() : "";

        //更改当前会员的上级，和目录树;更新relation表
        String oldPath = user.getTreePath();
        String newPath = targetParentUser.getTreePath() + user.getUserId() + "|";
        this.updateParentAndPathAndRelation(user.getUserId(), targetParentUser.getUserId(), newPath);

        //查出所有他的团队会员，嫁接上新的目录树;更新relation表
        List<UserPO> teamUserList = userRepository.getTeamUserList(user.getUserId(), user.getTreePath());
        for (UserPO teamUser : teamUserList) {
            String tempPath = teamUser.getTreePath().replace(oldPath, newPath);
            userRepository.updatePath(teamUser.getUserId(), tempPath);
        }

        //记录变更日志
        String text = String.format("原上级:%s(%s)[%s]，变更后:%s(%s)[%s]", oldParentName, oldParentId.toString(), oldRealName,
                targetParentUser.getMobile(), targetParentUser.getUserId().toString(), targetParentUser.getRealName());
        changeUserLog(user, UserChangeLogType.CHANGE_PARENT, text);
        return new TwoTuple<>(true, "");
    }

    private void updateParentAndPathAndRelation(Long userId, Long newParentId, String newPath) {
        //更新当前用户上级与path
        userRepository.updatePath(userId, newPath, newParentId);

        //解除oldPath关联表
        userRelaxRepository.deleteByChild(userId);

        //添加newPath关联表
        newPath = StringUtilsExt.ltrim(newPath, '|');
        newPath = StringUtilsExt.rtrim(newPath, '|');
        String[] arrNewPath = newPath.split("\\|");
        List<String> pathList = Arrays.asList(arrNewPath);
        Collections.reverse(pathList);
        for (int i = 0; i < pathList.size(); i++) {
            if (pathList.get(i).equals(userId.toString())) {
                continue;
            }
            Long pid = Long.valueOf(pathList.get(i));
            UserPO tempParent = findById(pid);
            UserRelax relationsPO = new UserRelax();
            relationsPO.setChildId(userId);
            relationsPO.setDepth(i);
            relationsPO.setParent(tempParent);
            userRelaxRepository.save(relationsPO);
        }
    }


    /**
     * 升级用户为新秀会员，支付288成功后调用
     *
     * @param userId
     */
    @Override
    public void modifyUserType(Long userId) {
        UserPO user = findById(userId);
        if (user == null || user.getUserLevel().getCode() >= UserEnums.UserLevel.LEVEL_XIN_XIU.getCode()) {
            return;
        }
        userRepository.modifyUserType(userId, UserEnums.UserType.MEMBER, UserEnums.UserLevel.LEVEL_XIN_XIU);
    }

    /**
     * 修改会员等级
     *
     * @param userId
     */
    @Override
    public void modifyUserLevel(Long userId, UserEnums.UserLevel userLevel) {
        /**
         * 首先，先找到触发人，然后
         *
         */
        UserPO user = findById(userId);
        if (user == null) {
            return;
        }

        if (user.getUserLevel().getCode() >= userLevel.getCode()) {
            //如果修改的等级比用户当前等级小或等于，则不处理
            return;
        }

        if (userLevel.getCode().equals(UserEnums.UserLevel.LEVEL_DA_REN.getCode()) || userLevel.getCode().equals(UserEnums.UserLevel.LEVEL_XIN_XIU.getCode())) {
            userRepository.modifyUserType(userId, UserEnums.UserType.MEMBER, userLevel);
        } else {
            userRepository.modifyUserType(userId, UserEnums.UserType.GENERAL, userLevel);
        }
    }


    /**
     * 修改用户日志
     *
     * @param user
     * @param changeLogType
     * @param text
     */
    private void changeUserLog(UserPO user, UserChangeLogType changeLogType, String text) {
        //记录变更日志
        UserChangeLogPO changeLogPO = new UserChangeLogPO();
        changeLogPO.setUser(user);


//        if (manager != null) {
//            changeLogPO.setOpName(manager.getUsername());
//            changeLogPO.setOpId(manager.getUserId());
//        } else {
//            changeLogPO.setOpName("");
//            changeLogPO.setOpId(0);
//        }
        changeLogPO.setLogType(changeLogType);
        changeLogPO.setCreateTime(LocalDateTime.now());
        changeLogPO.setLogText(text);
        userChangeLogRepository.save(changeLogPO);
    }

    /**
     * 修改用户有效订单总金额
     *
     * @param userId
     * @param money  扣除为负数， 添加为正数
     */
    @Override
    public void modifyValidPayOrderSum(Long userId, BigDecimal money) {
        userRepository.modifyValidPayOrderSum(userId, money);
    }

    /**
     * 升级成功
     *
     * @param userId
     * @param bizOrderId
     */
    @Override
    public void upgradeSuccess(Long userId, String bizOrderId) {
        //修改用户支付状态
        userRepository.modifyMerchantPay(userId, true);
        //升级为新秀
        modifyUserLevel(userId, UserEnums.UserLevel.LEVEL_XIN_XIU);

        UserPO user = this.findById(userId);
        if (user == null) {
            throw new ApiException(ApiResult.error("用户不存在"));
        }
        //如果没有上线，则直接结束流程
        if (!user.isExistParent()) {
            return;
        }
        //我的上线
        UserPO parentPO = this.findById(user.getParentId());

        /**
         * 邀请开店成功后，给上线奖励100
         */

        BasicsConfig basicsConfig = baseConfigService.getConfig().getBasicsConfig();
        modifyUserBalance(bizOrderId, parentPO.getUserId(), basicsConfig.getInviteReward());
        //如果上线是达人身份 或没有上上线，则结束流程
        if (parentPO.getUserLevel().equals(UserEnums.UserLevel.LEVEL_DA_REN) || !parentPO.isExistParent()) {
            return;
        }

        //获取上线整条线的用户ID
        List<Long> parentIds = parentPO.getSuperiorUserIdList();
        List<UserPO> list = userRepository.getUserList(parentIds);
        Collections.reverse(list);
        //获取第一条达人数据
        UserPO daren = list.stream().filter(item -> item.getUserLevel().equals(UserEnums.UserLevel.LEVEL_DA_REN)).findFirst().orElse(null);
        if (daren == null) {
            return;
        }
        modifyUserBalance(bizOrderId, daren.getUserId(), basicsConfig.getInviteRewardBelong());
    }

    @Override
    public void addOrderAmount(Long userId, BigDecimal amount) {
        userRepository.addOrderAmount(amount, userId);
    }

    @Override
    @Transactional
    public void settleBalance(Long userId, BigDecimal amount, String subOrderId) {
        //待转正扣除
        ModifyBalanceDTO modifyBalanceDTO = new ModifyBalanceDTO();
        modifyBalanceDTO.setId(userId);
        modifyBalanceDTO.setOrderId(subOrderId);
        modifyBalanceDTO.setAmount(amount.negate());
        modifyBalanceDTO.setLogType(AdvanceLogType.LOG_TYPE3);
        modifyBalanceInFuture(modifyBalanceDTO);
        //余额增加
        modifyBalanceDTO.setAmount(amount);
        modifyBalanceDTO.setLogType(AdvanceLogType.LOG_TYPE2);
        this.modifyBalance(modifyBalanceDTO);
    }

    private void modifyUserBalance(String bizOrderId, Long userId, BigDecimal reward) {
        ModifyBalanceDTO dto = new ModifyBalanceDTO();
        dto.setOrderId(bizOrderId);
        dto.setLogType(AdvanceLogType.INVITE_REWARD);
        dto.setRemark("邀请奖励");
        dto.setAmount(reward);
        dto.setOpName("系统");
        dto.setId(userId);
        modifyBalance(dto);

    }


    @Override
    public UserStatisticsVO getStatisticsData() {
        UserStatisticsVO vo = new UserStatisticsVO();

        vo.setTotalUserNum(repository.count());

        LocalDateTime end = Jsr310Utils.DateTime.lastOfDay(LocalDateTime.now());
        LocalDateTime begin = Jsr310Utils.DateTime.startOfDay(end.minusDays(1));
        String beginTime = Jsr310Utils.DateTime.asString(begin);
        String endTime = Jsr310Utils.DateTime.asString(end);

        //今日，昨日数据
        String sql = "select ifnull(count(1), 0) as totalNum, DATE(create_time) as createTime " +
                "from zb_user " +
                "where create_time >= '" + beginTime + "' " +
                "  and create_time <= '" + endTime + "' " +
                " group by DATE(create_time) ";

        List<SqlDataReader> readers = executeReaderList(sql);
        for (SqlDataReader reader : readers) {
            if (beginTime.contains(reader.getString("createTime"))) {
                //昨日的
                vo.setTotalUserNumNewY(reader.getLong("totalNum"));
            } else {
                vo.setTotalUserNumNew(reader.getLong("totalNum"));
            }
        }
        return vo;
    }

    /**
     * 升级成达人身份
     */
    @Override
    public void upgradeDrLevel() {
        try {
            //查询等级是新秀的会员
            List<UserPO> userPOS = userRepository.findByUserTypeAndUserLevel(UserEnums.UserType.MEMBER, UserEnums.UserLevel.LEVEL_XIN_XIU);
            if (userPOS == null || userPOS.size() == 0) {
                return;
            }
            for (UserPO user : userPOS) {
                TeamSummaryVO vo = inviteSummary(user.getUserId(), true);
                //专属粉丝大于等于1000，并且会员用户大于等于100
                if (vo.getBuyer().getCount() >= 1000 && vo.getMerchant().getCount() >= 100) {
                    userRepository.upgradeDrLevel(user.getUserId(), UserEnums.UserLevel.LEVEL_DA_REN);
                }
            }
        } catch (Exception ex) {
            log.error("upgradeLevel", ex);
        }
    }

}
